package com.ecommerce.service.async;

import com.ecommerce.constant.AsyncTaskStatusEnum;
import com.ecommerce.service.AsyncTaskManager;
import com.ecommerce.vo.AsyncTaskInfo;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * 异步任务执行监控切面
 */
@Slf4j
@Aspect
@Component
public class AsyncTaskMonitor {

    // 注入异步任务执行管理器
    private final AsyncTaskManager asyncTaskManager;

    public AsyncTaskMonitor(AsyncTaskManager asyncTaskManager) {
        this.asyncTaskManager = asyncTaskManager;
    }

    /**
     * 异步任务执行的环绕切面
     */
    @Around("execution(* com.ecommerce.service.async.AsyncServiceImpl.*(..))")
    public Object taskHandle(ProceedingJoinPoint proceedingJoinPoint) {
        // 获取taskId, 调用异步任务传入的第二个参数
        String taskId = proceedingJoinPoint.getArgs()[1].toString();

        // 获取任务信息, 在提交任务的时候就已经放入到容器中了
        AsyncTaskInfo asyncTaskInfo = asyncTaskManager.getTaskInfo(taskId);
        log.info("AsyncTaskMonitor is monitoring async task: [{}]", taskId);

        asyncTaskInfo.setStatus(AsyncTaskStatusEnum.RUNNING);
        asyncTaskManager.setTaskInfo(asyncTaskInfo);

        AsyncTaskStatusEnum status;
        Object result;

        try{
            // 执行异步任务
            result = proceedingJoinPoint.proceed();
            status = AsyncTaskStatusEnum.SUCCESS;
        } catch (Throwable ex) {
            // 异步任务出现异常
            result = null;
            status = AsyncTaskStatusEnum.FAILED;
            log.error("AsyncTaskMonitor: async task [{}] is failed, Error Info: [{}]", taskId, ex.getMessage(), ex);
        }

        // 设置异步任务其他信息，并再次放入容器
        asyncTaskInfo.setEndTime(new Date());
        asyncTaskInfo.setStatus(status);
        asyncTaskInfo.setTotalTime(String.valueOf(
                asyncTaskInfo.getEndTime().getTime() - asyncTaskInfo.getStartTime().getTime())
        );
        asyncTaskManager.setTaskInfo(asyncTaskInfo);

        return result;
    }
}
